<script setup>
import { useCameraStore } from '@/stores';
import { ref, reactive, computed, onMounted, onBeforeUnmount, onErrorCaptured } from 'vue';
import { useRouter } from 'vue-router';
import { useRoute } from 'vue-router';
const baseURL = import.meta.env.VITE_WS_BASE_URL;

const router = useRouter();
const route = useRoute();
const mode = route.query.mode;
const cameraStore = useCameraStore();

// DOM元素引用
const videoElement = ref(null);
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');

// 状态管理
const processedImageSrc = ref('');
const isProcessing = ref(false);
const errorMessage = ref('');
let mediaStream = null;
let ws = null;
let frameIntervalId = null;
let lastFrameTime = 0;
let tempFrameUrls = new Set(); // 跟踪临时URL，防止内存泄漏
let curBlob = null;

// 配置参数
const FPS = 10; // 调整为合适的帧率，过高可能导致延迟
const FRAME_INTERVAL = 1000 / FPS; // 帧间隔(ms)
const MAX_FRAME_DELAY = 200; // 最大允许的帧延迟(ms)
const RECONNECT_DELAY = 3000; // WebSocket重连延迟(ms)

// WebSocket连接
const connectWebSocket = () => {
  if (ws && [WebSocket.CONNECTING, WebSocket.OPEN].includes(ws.readyState)) {
    return; // 已有活跃连接，不重复创建
  }

  try {
    ws = new WebSocket(`${baseURL}/video/ws/camera`);
    
    ws.onopen = () => {
      isProcessing.value = true;
      startFrameCapture();
    };

    ws.onmessage = (event) => {
      // 接收处理后的帧并优化显示
      const now = Date.now();
      curBlob = new Blob([event.data], { type: 'image/jpeg' });
      const url = URL.createObjectURL(curBlob);
      
      // 防止过快更新导致卡顿，丢弃延迟过高的帧
      if (now - lastFrameTime < MAX_FRAME_DELAY) {
        // 使用requestAnimationFrame确保平滑渲染
        requestAnimationFrame(() => {
          // 释放上一帧的URL
          if (processedImageSrc.value) {
            tempFrameUrls.delete(processedImageSrc.value);
            URL.revokeObjectURL(processedImageSrc.value);
          }
          processedImageSrc.value = url;
          tempFrameUrls.add(url);
        });
      } else {
        // 丢弃延迟帧
        URL.revokeObjectURL(url);
      }
      lastFrameTime = now;
    };

    ws.onerror = (error) => {
      errorMessage.value = `WebSocket错误: ${error.message}`;
    };

    ws.onclose = (event) => {
      console.log(`WebSocket关闭，代码=${event.code} 原因=${event.reason}`);
      isProcessing.value = false;
      // 自动重连
      setTimeout(connectWebSocket, RECONNECT_DELAY);
    };
  } catch (err) {
    console.error('创建WebSocket失败:', err);
    errorMessage.value = `连接失败: ${err.message}`;
    setTimeout(connectWebSocket, RECONNECT_DELAY);
  }
};

// 开启摄像头
const startCamera = async () => {
  try {
    mediaStream = await navigator.mediaDevices.getUserMedia({ audio: false, video: true });
    videoElement.value.srcObject = mediaStream;
    
    // 设置canvas尺寸与视频一致
    await new Promise(resolve => {
      videoElement.value.onloadedmetadata = () => {
        canvas.width = videoElement.value.videoWidth;
        canvas.height = videoElement.value.videoHeight;
        resolve();
      };
    });
  } catch (error) {
    console.error('摄像头错误:', error);
    errorMessage.value = `摄像头错误: ${error.message}`;
    throw error; // 向上传播错误
  }
};

// 帧捕获与发送（使用固定间隔，避免异步累积延迟）
const captureAndSendFrame = () => {
  if (!videoElement.value || !ctx || !ws || ws.readyState !== WebSocket.OPEN) {
    return;
  }

  // 绘制当前帧到canvas
  ctx.drawImage(videoElement.value, 0, 0, canvas.width, canvas.height);

  // 使用toDataURL同步方法（性能略低但帧率更稳定）
  const dataUrl = canvas.toDataURL('image/jpeg', 0.6);
  const binary = atob(dataUrl.split(',')[1]);
  const array = new Uint8Array(binary.length);
  
  for (let i = 0; i < binary.length; i++) {
    array[i] = binary.charCodeAt(i);
  }

    // 发送帧数据
  ws.send(selectedEffect.value);

  // 发送帧数据
  ws.send(array.buffer);
};

// 开始帧捕获
const startFrameCapture = () => {
  // 清除旧定时器
  if (frameIntervalId) {
    clearInterval(frameIntervalId);
  }
  
  // 使用固定间隔定时器（更可靠的帧率控制）
  frameIntervalId = setInterval(captureAndSendFrame, FRAME_INTERVAL);
};

// 组件生命周期
onMounted(async () => {
  try {
    await startCamera();
    connectWebSocket();
  } catch (err) {
    errorMessage.value = `初始化失败: ${err.message}`;
  }
});

onBeforeUnmount(() => {
  // 清理所有资源
  if (frameIntervalId) clearInterval(frameIntervalId);
  if (mediaStream) mediaStream.getTracks().forEach(track => track.stop());
  if (ws) ws.close();
  
  // 释放所有临时URL
  tempFrameUrls.forEach(url => URL.revokeObjectURL(url));
  tempFrameUrls.clear();
});

// 错误捕获
onErrorCaptured((err) => {
  console.error('组件错误:', err);
  errorMessage.value = `运行时错误: ${err.message}`;
  return false; // 继续传播错误
});

// 特效参数
const effectParams = reactive({
  brightness: 100,
  contrast: 100,
  saturate: 100,
  grayscale: 0,
  hueRotate: 0
});

// 预设特效
const presetEffects = [
  { label: '原图', name: 'o' },
  { label: '灰度', name: 'gray'},
  { label: '模糊', name: 'blur' },
  { label: '磨皮', name: 'skin_smoothing' },
  { label: '美白', name: 'whitening' },
  { label: '锐化', name: 'sharpen' },
  { label: '暖色', name: 'warm' },
  { label: '冷色', name: 'cold' },
  { label: '边缘检测', name: 'edge' },
  { label: '反色效果', name: 'invert' },
  { label: '铅笔素描', name: 'sketch' },
  { label: '老电影', name: 'old_movie' },
  { label: 'HDR', name: 'hdr' },
  { label: '卡通化', name: 'cartoon' },
  { label: '高对比度', name: 'high_contrast' },
  { label: '棕褐色调', name: 'sepia' },
  { label: 'LOMO', name: 'lomo' },
  { label: '褪色', name: 'fade' },
  { label: '红色滤镜', name: 'red_filter' },
  { label: '雨滴', name: 'rain' },
  { label: '动态模糊', name: 'motion_blur' },
  { label: '像素化', name: 'pixelate' },
  { label: '柔光', name: 'soft_glow' }
];

// 控制参数配置
const effectControls = [
  { prop: 'brightness', label: '亮度', min: 0, max: 200, step: 1 },
  { prop: 'contrast', label: '对比度', min: 0, max: 200, step: 1 },
  { prop: 'saturate', label: '饱和度', min: 0, max: 200, step: 1 },
  { prop: 'hueRotate', label: '色相', min: 0, max: 360, step: 1 }
];

// 计算视频样式
const videoStyles = computed(() => {
  return {
    filter: `
      brightness(${effectParams.brightness}%)
      contrast(${effectParams.contrast}%)
      saturate(${effectParams.saturate}%)
      grayscale(${effectParams.grayscale}%)
      hue-rotate(${effectParams.hueRotate}deg)
    `
  };
});

// 应用预设特效
const selectedEffect = ref('');
const applyPresetEffect = (effect) => {
  if (effect.name === 'reset') {
    Object.assign(effectParams, {
      brightness: 100,
      contrast: 100,
      saturate: 100,
      grayscale: 0,
      hueRotate: 0
    });
    return;
  }
};

// 最近拍摄的照片列表
const recentPhotos = ref([]);

// 拍照功能
const convertBlobToBase64 = (blob) => {
  return new Promise((resolve) => {
    const reader = new FileReader();
    reader.onloadend = () => resolve(reader.result);
    reader.readAsDataURL(blob);
  });
};

const capturePhoto = async () => {
  if (!curBlob || !processedImageSrc.value) return;
  
  if (mode === 'once') {
    const file = new File([curBlob], "image.png", {
      type: curBlob.type,
      lastModified: Date.now()
    });

    cameraStore.setCapturedImage(file);
    router.back();
    return;
  }

  // 保存到相册列表
  const url = await convertBlobToBase64(curBlob);
  recentPhotos.value.push({
    url: url,
    time: new Date()
  });
  
  // 限制最多保存10张
  if (recentPhotos.value.length > 10) {
    recentPhotos.value.shift();
  }
  
  const link = document.createElement('a');
  link.download = `photo_${Date.now()}.jpg`;
  link.href = processedImageSrc.value;
  link.click();
};
</script>

<template>
  <div class="video-container">
    <!-- 视频播放区域 -->
    <div class="video-wrapper">
      <video 
        ref="videoElement"
        style="position: absolute; opacity: 0;"
        autoplay
        muted
        playsinline
      ></video>
      <img class="video-element" :style="videoStyles" :src="processedImageSrc">
    </div>

    <!-- 特效控制栏 -->
    <div class="effects-panel">
      <!-- 拍照按钮 -->
      <div style="display: flex; align-items: center; justify-content: center; margin-bottom: 15px;">
        <el-button type="primary" @click="capturePhoto">拍照</el-button>
      </div>
      <!-- 参数调节 -->
      <div class="effect-controls-container">
        <div class="effect-control" v-for="control in effectControls" :key="control.prop">
          <span class="label">{{ control.label }}:</span>
          <el-slider
            v-model="effectParams[control.prop]"
            :min="control.min"
            :max="control.max"
            :step="control.step"
            style="width: 150px"
          />
        </div>
      </div>
      <!-- 重置按钮保持原位 -->
      <div style="display: flex; align-items: center; justify-content: center;">
        <el-button @click="applyPresetEffect({'name': 'reset'})">重置</el-button>
        <el-radio-group v-model="selectedEffect">
          <el-radio-button :label="effect.name" 
            v-for="effect in presetEffects"
            :key="effect.name"
            >
            {{ effect.label }}
          </el-radio-button>
        </el-radio-group>
      </div>
    </div>

    <!-- 最近拍摄相册 -->
    <div class="photo-album" style="margin-top: 20px; padding: 10px; border-top: 1px solid #e4e7ed;">
      <h3 style="font-size: 16px; margin-bottom: 10px;">最近拍摄</h3>
      <el-row :gutter="10">
        <el-col v-for="(photo, index) in recentPhotos" :key="index" :span="6">
          <div class="photo-item" style="text-align: center;">
            <el-image :src="photo.url" :preview-src-list="[photo.url]" alt="拍摄照片" style="width: 200px; height: 200px; border-radius: 4px;"></el-image>
            <div style="font-size: 12px; color: #606266; margin-top: 5px;">{{ photo.time.toLocaleString() }}</div>
          </div>
        </el-col>
      </el-row>
    </div>
  </div>
</template>

<style scoped>
.video-container {
  max-width: 1200px;
  margin: 20px auto;
  padding: 20px;
}

.video-wrapper {
  background: #000;
  border-radius: 8px;
  overflow: hidden;
  margin-bottom: 20px;
}

.video-element {
  transform: scaleX(-1);
  width: 100%;
  height: 600px;
  object-fit: contain;
  transition: filter 0.3s ease;
}

.effects-panel {
  padding: 20px;
  background: #f5f7fa;
  border-radius: 8px;
}

.effect-controls-container {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 30px;
}

.effect-control {
  display: flex;
  align-items: center;
}

.prsetEffects-container {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
}

.label {
  min-width: 60px;
  font-size: 14px;
  color: #606266;
}
</style>